﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using S7.Net;
using S7PlcDataCollector.Client.Forms;
using S7PlcDataCollector.Models;
using S7PlcDataCollector.Service;
using S7PlcDataCollector.Service.PlcLink;
using ZbSkin.Frm;
using ZbSkin.Tools;
using Timer = System.Threading.Timer;

namespace S7PlcDataCollector.Client.Controls
{
    public partial class RealtimeDataControl : PageControl
    {
        private S7PlcEntity _currentS7PlcEntity;
        private PlcLinkState _currentLinkState = PlcLinkState.Unknown;

        private readonly SynchronizationContext _context;
        private readonly Timer _timer;
        private readonly List<S7PlcVariableEntityInfo> _s7PlcVariableEntityInfoList;

        private static readonly int VariableValueColumn = 3;

        public RealtimeDataControl()
        {
            InitializeComponent();
            _context = SynchronizationContext.Current;
            _timer = new Timer(TimerFunc, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
            _s7PlcVariableEntityInfoList = new List<S7PlcVariableEntityInfo>();
        }

        private void TimerFunc(object state)
        {
            foreach (var info in _s7PlcVariableEntityInfoList)
            {
                S7PlcDataCollectorService.Instance.GetVariable(info.Model);
            }
        }

        private void RealtimeDataControl_Load(object sender, EventArgs e)
        {
            DataGridViewHelper.SetCommonStyle(dataGridView);
            ResizeControls();

            var s7PlcEntityInfoList = new List<S7PlcEntityInfo>();
            var models = S7PlcDataCollectorService.Instance.GetS7PlcEntityList();
            foreach (var model in models)
            {
                s7PlcEntityInfoList.Add(new S7PlcEntityInfo()
                {
                    Model = model
                });
            }

            cmbPlcDevice.DataSource = s7PlcEntityInfoList;
            cmbPlcDevice.DisplayMember = "Device";
        }

        private void RealtimeDataControl_Resize(object sender, EventArgs e)
        {
            ResizeControls();
        }

        private void ResizeControls()
        {
            SetRegion();

            dataGridView.Width = ClientSize.Width - 40;
            dataGridView.Height = ClientSize.Height - dataGridView.Top - btnAdd.Height * 2;
            dataGridView.Left = 20;
            btnAdd.Top = ClientSize.Height - (int) (btnAdd.Height * 1.5f);
            btnDel.Top = btnAdd.Top;
            btnEdit.Top = btnAdd.Top;
        }

        protected override void ShowControl()
        {
            base.ShowControl();
            _timer.Change(TimeSpan.FromMilliseconds(0), TimeSpan.FromMilliseconds(1000));
            S7PlcDataCollectorService.Instance.LinkStateChangeEvent += OnLinkStateChange;
            S7PlcDataCollectorService.Instance.ReceivePlcDataEvent += OnReceivePlcData;
        }

        protected override void HideControl()
        {
            S7PlcDataCollectorService.Instance.LinkStateChangeEvent -= OnLinkStateChange;
            S7PlcDataCollectorService.Instance.ReceivePlcDataEvent -= OnReceivePlcData;
            _timer?.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
            base.HideControl();
        }

        private void cmbPlcDevice_SelectedValueChanged(object sender, EventArgs e)
        {
            _currentS7PlcEntity = (cmbPlcDevice.SelectedItem as S7PlcEntityInfo)?.Model;
            if (_currentS7PlcEntity == null)
            {
                UpdateLinkState(PlcLinkState.Unknown);
                return;
            }

            _currentLinkState = S7PlcDataCollectorService.Instance.GetLinkState(_currentS7PlcEntity.Rid);
            UpdateLinkState(_currentLinkState);

            UpdateDataGridView();
        }

        private void UpdateLinkState(PlcLinkState linkState)
        {
            _context?.Post((state) =>
            {
                _currentLinkState = (PlcLinkState) state;
                labelLinkState.Text = $@"连接状态：{_currentLinkState}";
            }, linkState);
        }

        private void dataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            UpdateS7PlcVariable();
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            UpdateS7PlcVariable();
        }

        private void btnDel_Click(object sender, EventArgs e)
        {
            var model = (dataGridView.CurrentRow?.DataBoundItem as S7PlcVariableEntityInfo)?.Model;
            if (model == null)
            {
                return;
            }

            var text = $@"确定要删除PLC变量[{model.Variable}]吗？";
            if (!MessageBoxEx.Question(text, ParentForm))
            {
                return;
            }

            if (S7PlcDataCollectorService.Instance.DeleteS7PlcVariableEntity(model))
            {
                UpdateDataGridView();
            }
            else
            {
                MessageBoxEx.Warning(@"删除PLC变量失败");
            }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (_currentS7PlcEntity == null)
            {
                MessageBoxEx.Warning("请选择PLC设备", ParentForm);
                return;
            }

            var form = new FrmPlcVariableSetup(_currentS7PlcEntity.Rid) {Owner = ParentForm};
            if (form.ShowDialog() == DialogResult.OK)
            {
                UpdateDataGridView();
            }
        }

        private void UpdateS7PlcVariable()
        {
            if (_currentS7PlcEntity == null)
            {
                MessageBoxEx.Warning("请选择PLC设备", ParentForm);
                return;
            }

            var model = (dataGridView.CurrentRow?.DataBoundItem as S7PlcVariableEntityInfo)?.Model;
            if (model == null)
            {
                return;
            }

            var form = new FrmPlcVariableSetup(model, _currentS7PlcEntity.Rid) {Owner = ParentForm};
            if (form.ShowDialog() == DialogResult.OK)
            {
                UpdateDataGridView();
            }
        }

        private void UpdateDataGridView()
        {
            dataGridView.DataSource = null;

            _s7PlcVariableEntityInfoList.Clear();
            var models = S7PlcDataCollectorService.Instance.GetS7PlcVariableEntityList(_currentS7PlcEntity.Rid);
            var index = 0;
            foreach (var model in models)
            {
                _s7PlcVariableEntityInfoList.Add(new S7PlcVariableEntityInfo()
                {
                    Model = model,
                    Index = ++index
                });
            }

            dataGridView.AutoGenerateColumns = false;
            dataGridView.DataSource = _s7PlcVariableEntityInfoList;
        }

        private void OnLinkStateChange(S7PlcEntity plcEntity, PlcLinkState linkState)
        {
            if (plcEntity == null || plcEntity.Rid != _currentS7PlcEntity.Rid)
            {
                return;
            }

            UpdateLinkState(linkState);
        }

        private void OnReceivePlcData(S7PlcVariableEntity variableEntity, PlcDataResult result)
        {
            if (variableEntity == null || variableEntity.S7PlcEntityRid != _currentS7PlcEntity.Rid)
            {
                return;
            }

            var index = -1;
            for (var i = 0; i < _s7PlcVariableEntityInfoList.Count; i++)
            {
                if (_s7PlcVariableEntityInfoList[i].Model != null &&
                    _s7PlcVariableEntityInfoList[i].Model.Rid == variableEntity.Rid)
                {
                    index = i;
                    break;
                }
            }

            if (index < 0)
            {
                return;
            }

            _s7PlcVariableEntityInfoList[index].Value = result.Ok ? result.Data : @"获取失败";
            _context?.Post((state) =>
            {
                var rowIndex = (int) state;
                dataGridView.UpdateCellValue(VariableValueColumn, rowIndex);
            }, index);
        }

        private class S7PlcEntityInfo
        {
            // ReSharper disable once UnusedMember.Global
            // ReSharper disable once UnusedMember.Local
            public string Device => $@"{Type} @ {Model?.Ip}.{Model?.Port}";
            private CpuType Type => Model?.TypeEnum ?? CpuType.S7200;
            public S7PlcEntity Model { get; set; }
        }

        private class S7PlcVariableEntityInfo
        {
            // ReSharper disable once UnusedAutoPropertyAccessor.Local
            public int Index { get; set; }

            // ReSharper disable once UnusedMember.Global
            // ReSharper disable once UnusedMember.Local
            public string Variable => Model?.Variable;

            // ReSharper disable once UnusedMember.Global
            // ReSharper disable once UnusedMember.Local
            public VarType VariableType => Model?.VariableTypeEnum ?? VarType.Bit;

            // ReSharper disable once UnusedMember.Global
            // ReSharper disable once UnusedMember.Local
            // ReSharper disable once UnusedAutoPropertyAccessor.Local
            public object Value { get; set; }
            public S7PlcVariableEntity Model { get; set; }
        }
    }
}
